package oakclub.model;

import oakclub.global.Enums;
import oakclub.entity.*;
import oakclub.global.Context;
import oakclub.jooq.Tables;
import oakclub.jooq.tables.*;
import oakclub.jooq.tables.records.UsersRecord;
import org.apache.commons.lang3.StringUtils;
import org.jooq.*;
import org.jooq.impl.DSL;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class UserModel extends BaseModel
{
    public UserEntity get(long userId) throws Exception
    {
        return (UserEntity) this.fetch(new IFetch()
        {
            @Override
            public Object fetch(DSLContext context, Object... params) throws Exception
            {
                // params
                long userId = (long) params[0];

                // table alias
                Users U = Tables.USERS;
                UserCoordinate UC = Tables.USER_COORDINATE;
                City C = Tables.CITY;
                Vips V = Tables.VIPS;
                UserVideo UV = Tables.USER_VIDEO;
                ChatAccounts CA = Tables.CHAT_ACCOUNTS;
                UsersCheckout UCH = Tables.USERS_CHECKOUT;
                Likes LI = Tables.LIKES;
                UserPhotos UP = Tables.USER_PHOTOS;
                Schools S = Tables.SCHOOLS;
                UsersSchools US = Tables.USERS_SCHOOLS;
                Employers E = Tables.EMPLOYERS;
                WorkHistory WH = Tables.WORK_HISTORY;
                Favorites F = Tables.FAVORITES;
                UsersFavorites UF = Tables.USERS_FAVORITES;

                // user info
                Record userRecord = context
                    .select(U.NAME, U.BIRTHDAY, U.GENDER, U.RELATIONSHIP_STATUS, U.INTERESTED, U.ETHNICITY, U.LANGUAGE, U.IS_PRIVATE)
                    .select(U.IS_ENABLED, U.IS_STAR, U.APPROVED, U.CREATED_TIME, U.USERNAME, U.EMAIL, U.IS_1ST_LOGIN)
                    .select(U.IS_VERIFY, U.FORCE_VERIFY, U.IS_SKIP_VERIFY, U.ABOUT_ME, U.WEIGHT, U.HEIGHT, U.LAST_LOGIN, U.AVATAR)
                    .select(UC.LATITUDE, UC.LONGITUDE)
                    .select(C.NAME, C.COUNTRY_NAME)
                    .select(DSL.decode().when(V.USER_ID.isNotNull(), 1).otherwise(0).as("is_vip"))
                    .select(UV.FILE, CA.USERNAME, CA.PASSWORD)
                    .select(context.selectCount().from(UCH).where(UCH.USER_ID.eq(userId)).asField("num_viewed"))
                    .select(context.selectCount().from(LI).where(LI.TARGET_ID.eq(userId), LI.IS_LIKE.eq((short) 1)).asField("num_liked"))
                    .from(U)
                    .leftOuterJoin(UC).on(UC.USER_ID.eq(U.USER_ID))
                    .leftOuterJoin(C).on(C.ID.eq(UC.CITY_ID))
                    .leftOuterJoin(V).on(V.USER_ID.eq(U.USER_ID), V.EXPIRE_DATE.gt(new Date().getTime()))
                    .leftOuterJoin(UV).on(UV.USER_ID.eq(U.USER_ID))
                    .leftOuterJoin(CA).on(CA.USER_ID.eq(U.USER_ID))
                    .where(U.USER_ID.eq(userId))
                    .limit(1)
                    .fetchOne();
                if(userRecord == null)
                {
                    return null;
                }

                // photo records
                Result<Record> photoRecords = context
                    .select()
                    .select(UP.ID, UP.PATH, UP.IS_AVATAR)
                    .from(UP)
                    .where(UP.USER_ID.eq(userId))
                    .fetch();

                // school records
                Result<Record> schoolRecords = context
                    .select()
                    .select(S.SCHOOL_ID, S.SCHOOL_NAME)
                    .from(US)
                    .join(S).on(S.SCHOOL_ID.eq(US.SCHOOL_ID))
                    .where(US.USER_ID.eq(userId))
                    .fetch();

                // work records
                Result<Record> workRecords = context
                    .select()
                    .select(E.EMPLOYER_ID, E.EMPLOYER_NAME)
                    .from(WH)
                    .join(E).on(E.EMPLOYER_ID.eq(WH.EMPLOYER_ID))
                    .where(WH.USER_ID.eq(userId))
                    .fetch();

                // parse
                UserEntity user = new UserEntity();
                user.setId(userId);
                user.setName(userRecord.getValue(U.NAME));
                user.setBirthday(userRecord.getValue(U.BIRTHDAY));
                user.setGender(new GenderEntity(userRecord.getValue(U.GENDER)));
                user.setRelationship(new RelationshipEntity(userRecord.getValue(U.RELATIONSHIP_STATUS)));
                user.setInterestedIn(new GenderEntity(userRecord.getValue(U.INTERESTED)));
                user.setEthnicity(new EthnicityEntity(userRecord.getValue(U.ETHNICITY)));
                user.setLanguages(new ArrayList<LanguageEntity>());
                user.setPrivate(userRecord.getValue(U.IS_PRIVATE) == 1);
                user.setEnabled(userRecord.getValue(U.IS_ENABLED) == 1);
                user.setStar(userRecord.getValue(U.IS_STAR) == 1);
                user.setApproved(userRecord.getValue(U.APPROVED) == 1);
                user.setCreatedTime(userRecord.getValue(U.CREATED_TIME));
                user.setUsername(userRecord.getValue(U.USERNAME));
                user.setEmail(userRecord.getValue(U.EMAIL));
                user.setFinishedRegister(userRecord.getValue(U.IS_1ST_LOGIN) == 5);
                user.setVerification(new VerificationEntity());
                user.setAboutMe(userRecord.getValue(U.ABOUT_ME));
                user.setWeight(userRecord.getValue(U.WEIGHT));
                user.setHeight(userRecord.getValue(U.HEIGHT));
                user.setLastLogin(userRecord.getValue(U.LAST_LOGIN));
                user.setAvatar(new PhotoEntity(user, userRecord.getValue(U.AVATAR)));
                user.setLocation(new LocationEntity());
                user.setVip(userRecord.getValue("is_vip") == 1);
                user.setVideo(new VideoEntity(userRecord.getValue(UV.FILE)));
                user.setXmpp(new XmppEntity(userRecord.getValue(CA.USERNAME), userRecord.getValue(CA.PASSWORD)));
                user.setNumViewed((int) userRecord.getValue("num_viewed"));
                user.setNumLiked((int) userRecord.getValue("num_liked"));
                user.setPhotos(new ArrayList<PhotoEntity>());
                user.setSchools(new ArrayList<SchoolEntity>());
                user.setWorks(new ArrayList<WorkEntity>());
                user.setFavorites(new ArrayList<FavoriteEntity>());

                VerificationEntity verification = user.getVerification();
                verification.setVerified(userRecord.getValue(U.IS_VERIFY) == 1);
                verification.setForced(userRecord.getValue(U.FORCE_VERIFY) == 1);
                verification.setSkipped(userRecord.getValue(U.IS_SKIP_VERIFY) == 0);

                LocationEntity location = user.getLocation();
                location.setLatitude(userRecord.getValue(UC.LATITUDE));
                location.setLongitude(userRecord.getValue(UC.LONGITUDE));
                location.setCity(new CityEntity(userRecord.getValue(C.NAME), userRecord.getValue(C.COUNTRY_NAME)));

                String languagesData = userRecord.getValue(U.LANGUAGE);
                if(languagesData != null && !languagesData.isEmpty())
                {
                    List<LanguageEntity> languages = user.getLanguages();

                    String[] names = languagesData.split(",");
                    for(String name : names)
                    {
                        if(StringUtils.isNumeric(name))
                        {
                            name = LanguageEntity.Language.getName(Integer.parseInt(name));
                        }
                        languages.add(new LanguageEntity(name));
                    }
                }

                List<PhotoEntity> photos = user.getPhotos();
                for(Record record : photoRecords)
                {
                    PhotoEntity photo = new PhotoEntity();
                    photo.setId(record.getValue(UP.ID));
                    photo.setPath(record.getValue(UP.PATH));
                    photo.setAvatar(record.getValue(UP.IS_AVATAR) == 1);
                    photo.setUser(user);
                    photos.add(photo);
                }

                List<SchoolEntity> schools = user.getSchools();
                for(Record record : schoolRecords)
                {
                    SchoolEntity school = new SchoolEntity();
                    school.setId(record.getValue(S.SCHOOL_ID));
                    school.setName(record.getValue(S.SCHOOL_NAME));
                    schools.add(school);
                }

                List<WorkEntity> works = user.getWorks();
                for(Record record : workRecords)
                {
                    WorkEntity work = new WorkEntity();
                    work.setId(record.getValue(E.EMPLOYER_ID));
                    work.setName(record.getValue(E.EMPLOYER_NAME));
                    works.add(work);
                }

                return user;
            }
        }, userId);
    }

    public void login(long userId, String deviceToken) throws Exception
    {
        this.execute(new IExecute()
        {
            @Override
            public void execute(DSLContext context, Object... params) throws Exception
            {
                // params
                long userId = (long) params[0];
                String deviceToken = (String) params[1];

                // table alias
                Users U = Tables.USERS;

                // update
                UpdateSetMoreStep<UsersRecord> updateSetMoreStep = context
                    .update(U)
                    .set(U.LAST_LOGIN, DSL.currentTimestamp());
                if(Context.get().getPlatformId() == Enums.Platform.IOS.val())
                {
                    context
                        .update(U)
                        .set(U.DEVICE_TOKEN, (String) null)
                        .where(U.DEVICE_TOKEN.eq(deviceToken))
                        .execute();

                    updateSetMoreStep.set(U.DEVICE_TOKEN, deviceToken);
                }
                else if(Context.get().getPlatformId() == Enums.Platform.ANDROID.val())
                {
                    context
                        .update(U)
                        .set(U.ANDROID_TOKEN, (String) null)
                        .where(U.ANDROID_TOKEN.eq(deviceToken))
                        .execute();

                    updateSetMoreStep.set(U.ANDROID_TOKEN, deviceToken);
                }
                updateSetMoreStep
                    .where(U.USER_ID.eq(userId))
                    .execute();
            }
        }, userId, deviceToken);
    }

    public void setLocale(long userId, String locale) throws Exception
    {
        this.execute(new IExecute()
        {
            @Override
            public void execute(DSLContext context, Object... params) throws Exception
            {
                // params
                long userId = (long) params[0];
                String locale = (String) params[1];

                // table alias
                Users U = Tables.USERS;

                // set language
                context
                    .update(U)
                    .set(U.LOCALE, locale)
                    .where(U.USER_ID.eq(userId))
                    .execute();
            }
        }, userId, locale);
    }

    public void verify(long userId) throws Exception
    {
        this.execute(new IExecute()
        {
            @Override
            public void execute(DSLContext context, Object... params) throws Exception
            {
                // params
                long userId = (long) params[0];

                // table alias
                Users U = Tables.USERS;

                // set language
                context
                    .update(U)
                    .set(U.IS_VERIFY, (short) 1)
                    .where(U.USER_ID.eq(userId))
                    .execute();
            }
        }, userId);
    }

    public void skipVerification(long userId) throws Exception
    {
        this.execute(new IExecute()
        {
            @Override
            public void execute(DSLContext context, Object... params) throws Exception
            {
                // params
                long userId = (long) params[0];

                // table alias
                Users U = Tables.USERS;

                // set language
                context
                    .update(U)
                    .set(U.IS_SKIP_VERIFY, (short) 0)
                    .where(U.USER_ID.eq(userId))
                    .execute();
            }
        }, userId);
    }
}
